/*******************************************************************************
 * @file    hwa_74hc595.c
 * @brief   74HC595移位寄存器驱动实现文件
 * @author  Talon
 * @date    2025/09/26
 * @version V1.0
 ******************************************************************************/
#include "hwa_74hc595.h"

/* Private variables ---------------------------------------------------------*/
static uint8_t u8_OutputCmd[NUM_OF_SR_SEL] = {0};  /* 存储每个移位寄存器的输出命令 */

/* Private macro -------------------------------------------------------------*/
#define SET_8BITS(var, bits) ((var) |= (bits))     /* 设置8位变量的指定位 */
#define CLR_8BITS(var, bits) ((var) &= (uint8_t) ~(bits)) /* 清除8位变量的指定位 */

/* Private functions ---------------------------------------------------------*/

/**
 * @brief   向74HC595发送一个字节的数据
 * @param   u8Data  要发送的数据
 * @retval  无
 * @note    此函数使用移位方式将数据逐位发送到74HC595，仅供内部调用
 */
static void hwa_74HC595Comm(uint8_t u8Data)
{
    uint8_t i = 0;

    /* 逐位发送数据，从最高位开始 */
    for (i = NUM_OF_SR_CHANNEL; i > 0; i--)
    {
        /* 设置数据位 */
        SR_DATA_SET((u8Data << (NUM_OF_SR_CHANNEL - i)) & 0x80 ? GPIO_PIN_SET : GPIO_PIN_RESET);

        /* 移位时钟脉冲 */
        SR_SHIFT_LOW();
        SR_DELAY_US(1);  /* 确保有足够的时间响应 */
        SR_SHIFT_HIGH();
    }
}

/* Exported functions --------------------------------------------------------*/

/**
 * @brief   控制指定级联芯片的指定通道开关
 * @param   sel     级联芯片选择
 * @param   channel 通道选择
 * @param   on_off  开关状态（1:开，0:关）
 * @retval  无
 */
void hwa_74HC595ChannelCtrl(SR_SEL_E sel, SR_CHANNEL_E channel, uint8_t on_off)
{
    if (on_off)
    {
        SET_8BITS(u8_OutputCmd[sel], 0x01 << channel);  /* 设置对应通道的位为1 */
    }
    else
    {
        CLR_8BITS(u8_OutputCmd[sel], 0x01 << channel);  /* 清除对应通道的位为0 */
    }
}

/**
 * @brief   74HC595定时处理函数，建议每10ms调用一次
 * @param   无
 * @retval  无
 * @note    此函数会将所有级联芯片的输出命令发送到硬件，并锁存输出
 */
void hwa_74HC595_Handler10ms(void)
{
    uint8_t i = 0;

    /* 依次向每个级联芯片发送数据 */
    for (i = NUM_OF_SR_SEL; i > 0; i--)
    {
        hwa_74HC595Comm(u8_OutputCmd[i - 1]);
    }

    /* 锁存数据，更新输出 */
    SR_LATCH_LOW();
    SR_DELAY_US(2);  /* 确保有足够的时间响应 */
    SR_LATCH_HIGH();
}

/**
 * @brief   将74HC595设置为睡眠模式
 * @param   无
 * @retval  无
 * @note    此函数会将所有控制引脚置低，以减少功耗
 */
void hwa_74HC595_Sleep(void)
{
    SR_DATA_LOW();
    SR_SHIFT_LOW();
    SR_LATCH_LOW();
}
